package my.design.synchronize;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 自定义锁，限制同时只能有两个线程获取资源（同一线程获取两次资源）
 * @author xsw
 * @date 2019年3月19日
 */
public class TwinsLock implements Lock{

	private static final class Sync extends AbstractQueuedSynchronizer{
		private static final long serialVersionUID = 1L;

		public Sync(int state){
			if(state <= 0){
				throw new IllegalArgumentException("state numbers must large than zero");
			}
			setState(state);
		}
		
		@Override
		protected int tryAcquireShared(int arg) {
			/*
			 * 1. 判断资源是否足够
			 * 2. 如果足够则尝试分配资源
			 * 3. 如果成功分配则返回，如果失败则重试
			 * 只有在两种情况返回，资源不足，或者成功获取资源。资源足够但获取失败的情况需要重试。
			 */
			for (;;) {
				int state = getState();
				int newState = state - arg;
				if(newState < 0 || compareAndSetState(state, newState)){
					return newState;
				}
			}
		}

		@Override
		protected boolean tryReleaseShared(int arg) {
			/*
			 * 取消资源占用也是并发的。需要重试。
			 * 取消资源占用一定成功。
			 */
			for(;;){
				int state = getState();
				int newState = state + arg;
				if(compareAndSetState(state, newState)){
					return true;
				}
			}
		}
		
		final ConditionObject newCondition() {
            return new ConditionObject();
        }
	}
	
	private final Sync sync = new Sync(2);
	
	@Override
	public void lock() {
		sync.acquireShared(1);
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {
		sync.acquireSharedInterruptibly(1);
	}

	@Override
	public boolean tryLock() {
		return sync.tryAcquireShared(1) >= 0;
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
	}

	@Override
	public void unlock() {
		sync.releaseShared(1);
	}

	@Override
	public Condition newCondition() {
		return sync.newCondition();
	}
	
}
